package definition

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"

	config "gitee.com/woodpile/wgs.ths.config.go"
)

type TemplateConfig struct {
	Dir []string `yaml:"dir,omitempty"`

	Ext []string `yaml:"ext,omitempty"`
}

func (*TemplateConfig) Name() string {
	return "template"
}

func (*TemplateConfig) ToDefault(cfg config.IConfigDefault) {
	ac := cfg.(*TemplateConfig)
	if len(ac.Dir) == 0 {
		ac.Dir = append(ac.Dir, "./template")
	}
	if len(ac.Ext) == 0 {
		ac.Ext = append(ac.Ext, ".tmpl")
	}
}

type TemplateManager struct {
	Config *TemplateConfig

	RootTemplate *template.Template
}

func NewTemplateManager() *TemplateManager {
	p := &TemplateManager{
		Config: GlobalConfig.Template,

		RootTemplate: template.New("root"),
	}

	return p
}

func LoadTemplate(ctx *Context) error {
	ctx.Template.RootTemplate.Funcs(PredefineTemplateFunc)
	for _, f := range ctx.FuncTemplateFunc {
		ctx.Template.RootTemplate.Funcs(f())
	}

	fCheck := func(fn string) bool {
		for _, ext := range GlobalConfig.Template.Ext {
			if filepath.Ext(fn) == ext {
				return true
			}
		}
		return false
	}
	fLoadTemplateFile := func(dir, fn string) error {
		fp := filepath.Join(dir, fn)
		templateName := strings.TrimSuffix(filepath.Base(fn), filepath.Ext(fn))

		fbs, err := os.ReadFile(fp)
		if err != nil {
			return err
		}
		if _, err := ctx.Template.RootTemplate.New(templateName).Parse(string(fbs)); err != nil {
			return fmt.Errorf("parse template file [%s] error: %s", templateName, err)
		}
		if GlobalConfig.Verbose {
			fmt.Printf("load template: [%s] %s\n", templateName, fp)
		}

		return nil
	}

	//加载模板
	for _, dir := range GlobalConfig.Template.Dir {
		if err := ForeachFileRecursively(dir, fCheck, fLoadTemplateFile); err != nil {
			return err
		}
	}

	return nil
}

var PredefineTemplateFunc = template.FuncMap{
	"BytesToString": func(bs []byte) string { return string(bs) },

	//std strings package
	"StringsToLower":      strings.ToLower,
	"StringsToUpper":      strings.ToUpper,
	"StringsCompare":      strings.Compare,
	"StringsContains":     strings.Contains,
	"StringsContainsAny":  strings.ContainsAny,
	"StringsCount":        strings.Count,
	"StringsFields":       strings.Fields,
	"StringsHasPrefix":    strings.HasPrefix,
	"StringsHasSuffix":    strings.HasSuffix,
	"StringsIndex":        strings.Index,
	"StringsIndexAny":     strings.IndexAny,
	"StringsJoin":         strings.Join,
	"StringsLastIndex":    strings.LastIndex,
	"StringsLastIndexAny": strings.LastIndexAny,
	"StringsRepeat":       strings.Repeat,
	"StringsReplace":      strings.Replace,
	"StringsReplaceAll":   strings.ReplaceAll,
	"StringsSplit":        strings.Split,
	"StringsSplitN":       strings.SplitN,
	"StringsSplitAfter":   strings.SplitAfter,
	"StringsSplitAfterN":  strings.SplitAfterN,
	"StringsToTitle":      strings.ToTitle,
	"StringsTrim":         strings.Trim,
	"StringsTrimLeft":     strings.TrimLeft,
	"StringsTrimPrefix":   strings.TrimPrefix,
	"StringsTrimRight":    strings.TrimRight,
	"StringsTrimSpace":    strings.TrimSpace,
	"StringsTrimSuffix":   strings.TrimSuffix,

	//std strconv package
	"StrconvFormatInt":   strconv.FormatInt,
	"StrconvFormatUint":  strconv.FormatUint,
	"StrconvFormatFloat": strconv.FormatFloat,
	"StrconvFormatBool":  strconv.FormatBool,
	"StrconvItoa":        strconv.Itoa,

	//custom functions
	"StringsToFirstUpper": func(str string) string {
		if len(str) == 0 {
			return str
		}
		return strings.ToUpper(str[0:1]) + str[1:]
	},
}
